<template>
  <div>
    <el-tabs v-model="activeTabName" closable @tab-click='handleTabClick' @tab-remove='handleTabRemove'>
      <el-tab-pane v-for="item in openedGraphTabs" :key="item.id" :name="item.id" :label="item.title">
        <span slot="label"><i :class="item.paneClass"></i>&nbsp;{{ item.title }}</span>
      </el-tab-pane>
    </el-tabs>
    
    <div id='graphPanel'  @drop="handleTargetDrop" @dragover="handleTargetDragOver" 
      v-show="openedGraphTabs.length > 0" style='border: 1px solid red;'>
      <div id='graphContainer' class='app-content'></div>
      <div id='miniMapContainer' class='map-container'></div>
    </div>

    <canvas id="canvasDiv" width="300" height="0" style="visibility: hidden;"></canvas>

    <custom-node-dialog v-if="customNodeDialogVisible" ref="customNodeDialog" 
      @submitOk="handleCustomNodeDialogSubmit"></custom-node-dialog>

    <select-device-dialog v-if="selectDeviceDialogVisible" ref="selectDeviceDialog" 
      @submitOk="handleSelectDeviceDialogSubmit">
    </select-device-dialog>

    <div v-show="menuVisible">
      <el-menu id="menu" class="menu" @select="handleContextMenuSelect">
        <el-menu-item index="copy" class="menu_item">
          <i class="el-icon-document-copy"></i>
          <span slot="title">复制</span>
        </el-menu-item>
        <el-menu-item index="cut" class="menu_item">
          <i class="el-icon-scissors"></i>
          <span slot="title">剪切</span>
        </el-menu-item>
        <el-menu-item index="paste" class="menu_item">
          <i class="el-icon-bangzhu"></i>
          <span slot="title">粘贴</span>
        </el-menu-item>
        <el-divider class="menu_divider"></el-divider>
        <el-menu-item index="customNode" class="menu_item">
          <i class="el-icon-edit-outline"></i>
          <span slot="title">生成自定义节点</span>
        </el-menu-item>
        <el-menu-item index="selectDevice" class="menu_item">
          <i class="el-icon-s-tools"></i>
          <span slot="title">选择设备</span>
        </el-menu-item>
        <el-divider class="menu_divider"></el-divider>
        <el-menu-item index="delete" class="menu_item">
          <i class="el-icon-delete"></i>
          <span slot="title">删除</span>
        </el-menu-item>
      </el-menu>
    </div>
  </div>
</template>

<script>
import { Graph } from '@antv/x6/lib/index'
import $ from 'jquery'
var _ = require('lodash')

import GraphUtil from '@/utils/graph-utils/graphUtil'
import ConfigUtil from '@/utils/graph-utils/configUtil'
import EventUtil from '@/utils/graph-utils/eventUtil'
import ConstantUtil from '@/utils/graph-utils/constantUtil'
import ShapeUtil from '@/utils/graph-utils/shapeUtil'
import GraphBehavier from '@/utils/graph-utils/graphBehavier'
import HeaderUtil from '@/utils/graph-utils/headerUtil'
import CustomNodeDialog from '@/views/drawTool/dialog/custom-node-dialog.vue'
import SelectDeviceDialog from '@/views/drawTool/dialog/select-device-dialog.vue'

import { getGraphFile } from '@/api/draw.js'

export default {
  name: 'GraphPanel',
  components: { CustomNodeDialog, SelectDeviceDialog },
  data() {
    return {
      activeTabName: '',
      openedGraphTabs: [],

      graph: null,
      contextMenuNode: null, // 操作右键菜单的节点

      customNodeDialogVisible: false,
      selectDeviceDialogVisible: false,
      menuVisible: false
    }
  },
  watch: {
    '$store.state.graphModule.graphFiles': function(files) {
      const self = this
      for (const file of files) {
        const index = self.openedGraphTabs.findIndex((value) => {
          return value.id === file.id
        })
        if (index === -1) {
          const graphTab = _.cloneDeep(file)
          graphTab.paneClass = 'el-icon-check'
          self.openedGraphTabs.push(graphTab)
          self.change2CurrentGraphFile(file.title)
        }
      }
    }
  },
  mounted() {
    const self = this
    const graphContainer = document.getElementById('graphContainer')
    const miniMapContainer = document.getElementById('miniMapContainer')
    const graphConfig = ConfigUtil.getDefaultGraphConfig()
    graphConfig.container = graphContainer
    graphConfig.minimap.container = miniMapContainer
    const graph = new Graph(graphConfig)
    this.graph = graph
    this.$store.commit('setGraph', graph)
    GraphBehavier.applyGraphEvents(graph, self)

    // 移动小地图的位置
    const windowHeight = $(window).height()
    $('#miniMapContainer').css('top', -1 * (windowHeight - 150) + 'px')

    // 添加定时器，校验图形是否修改
    self.timeId = setInterval(function() {
      self.checkGraphContentState()
    }, 5000)
  },
  beforeDestroy() {
    const self = this
    if (self.timeId) {
      clearInterval(self.timeId)
    }

    // 清除图形缓存
    if (self.openedGraphTabs.length !== 0) {
      for (const tab of self.openedGraphTabs) {
        GraphUtil.removeLocalstorageItem(tab.id)
      }
    }
  },
  methods: {
    handleTargetDrop(e) {
      const data = e.dataTransfer.getData('text/plain')
      const content = JSON.parse(data) // 这个就是树上的节点数据

      const localPoint = this.graph.clientToLocal(e.clientX, e.clientY)
      const nodes = this.graph.getNodesFromPoint(localPoint)
      if (nodes.length !== 0) {
        const node = nodes[0]
        if (!node.data) {
          node.data = {}
        }
        node.data.id = content.id
        if (content.properties.type === 'device') {
          node.data.devName = content.label
        }
        if (content.properties.type === 'analog') {
          node.data.name = content.label
        }
      }
    },

    handleTargetDragOver(e) {
      e.preventDefault()

      if (this.previousNode) {
        GraphBehavier.unhighlighterNode(this.previousNode)
      }

      const localPoint = this.graph.clientToLocal(e.clientX, e.clientY)
      const nodes = this.graph.getNodesFromPoint(localPoint)
      if (nodes.length !== 0) {
        const node = nodes[0]
        // 高亮当前元素
        GraphBehavier.highlighterNode(node)
        this.previousNode = node
      }
    },

    foo() {
      // 取消鼠标监听事件 菜单栏
      this.menuVisible = false
      document.removeEventListener('click', this.foo) // 要及时关掉监听，不关掉的是一个坑，不信你试试，虽然前台显示的时候没有啥毛病，加一个alert你就知道了
    },

    styleMenu(menu) {
      if (event.clientX > 800) {
        menu.style.left = event.clientX - 200 + 'px'
      } else {
        menu.style.left = event.clientX + 1 + 'px'
      }
      document.addEventListener('click', this.foo) // 给整个document新增监听鼠标事件，点击任何位置执行foo方法
      if (event.clientY > 650) {
        menu.style.top = event.clientY - 200 + 'px'
      } else {
        menu.style.top = event.clientY - 10 + 'px'
      }
    },

    // 判断文件内容是否修改
    isGraphContentModified(graphId, graphContent) {
      return new Promise((resolve, reject) => {
        getGraphFile(graphId).then(response => {
          if (!response.data || !response.data.jsonContent ||
          response.data.jsonContent.content !== graphContent) {
            resolve()
          } else {
            reject()
          }
        })
      })
    },

    // 检查图形文件是否修改
    checkGraphContentState() {
      const self = this
      for (const tab of self.openedGraphTabs) {
        let graphContent = ''
        if (tab.id === self.activeTabName) {
          graphContent = ConstantUtil.stringifyJson(self.graph.toJSON())
        } else {
          graphContent = GraphUtil.getLocalstorageItem(tab.id)
        }
        self.isGraphContentModified(tab.id, graphContent).then(() => {
          _.set(tab, 'paneClass', 'el-icon-edit')
        }).catch(() => {
          _.set(tab, 'paneClass', 'el-icon-check')
        })
      }
    },

    // 处理右键菜单选项
    handleContextMenuSelect(index, indexPath) {
      if (index === 'customNode') {
        this.handleShowCreateNodeDialog()
      } else if (index === 'selectDevice') {
        this.handleShowSelectDeviceDialog()
      } else if (index === 'copy') {
        HeaderUtil.handleCopy(this.graph)
      } else if (index === 'cut') {
        HeaderUtil.handleCut(this.graph)
      } else if (index === 'paste') {
        HeaderUtil.handlePaste(this.graph)
      } else if (index === 'delete') {
        HeaderUtil.handleDelete(this.graph)
      }
    },

    // 显示自定义子对话框
    handleShowCustomNodeDialog() {
      this.customNodeDialogVisible = true
      this.$nextTick(() => {
        this.$refs.customNodeDialog.showDialog()
      })
    },

    handleCustomNodeDialogSubmit(form) {
      EventUtil.createCustomNode(this, this.graph, form)
    },

    handleShowSelectDeviceDialog() {
      this.selectDeviceDialogVisible = true
      this.$nextTick(() => {
        this.$refs.selectDeviceDialog.showDialog(this.contextMenuNode)
      })
    },

    handleSelectDeviceDialogSubmit(treeNode) {
      if (!this.contextMenuNode) {
        return
      }
      if (!this.contextMenuNode.data) {
        this.contextMenuNode.data = {}
      }
      const metaType = this.contextMenuNode.data.metaType
      if (this.contextMenuNode.isEdge() || ConstantUtil.isElectricType(metaType) || ConstantUtil.isFaultType(metaType)) {
        this.contextMenuNode.data.id = treeNode.id
        this.contextMenuNode.data.name = treeNode.label
      } else if (ConstantUtil.isChannelType(metaType)) {
        this.contextMenuNode.data.savedRtus = treeNode.id
      } else if (ConstantUtil.isConditionType(metaType)) {
        // 配置工况节点时，所选中的节点可能为多个
        const value = treeNode.map(node => { return node.id }).join(',')
        this.contextMenuNode.data.savedRtus = value
      }
      this.contextMenuNode.data.isSaved = 'true'

      // 配置设备后，更新节点的显示属性
      const color = ConstantUtil.getConfigedColor(metaType)
      if (color) {
        if (this.contextMenuNode.isEdge()) {
          ShapeUtil.setNodeAttr(this.contextMenuNode, 'stroke', color)
        } else {
          ShapeUtil.setNodeAttr(this.contextMenuNode, 'fill', color)
          ShapeUtil.setNodeAttr(this.contextMenuNode, 'stroke', color)
        }
      }
    },

    handleTabClick(tab) {
      const self = this
      // 判断所点击tab是否与当前窗口一致，如果一致则不进行任何处理
      const oldGraphFile = self.$store.state.graphModule.currentGraphFile
      if (oldGraphFile && oldGraphFile.title === tab.name) {
        return
      }
      self.change2CurrentGraphFile(tab.label)
    },

    handleTabRemove(tabId) {
      const self = this
      // 如果文件被修改，则提示是否需要保存
      var jsonContent = ConstantUtil.stringifyJson(self.graph.toJSON())
      self.isGraphContentModified(tabId, jsonContent).then(() => {
        self.$confirm('是否需要保存当前图形?', '保存确认', {}).then(() => {
          HeaderUtil.handleSave(self, self.graph, false)
          self.closeGraphFile(tabId)
        }).catch(() => {
          self.closeGraphFile(tabId)
        })
      }).catch(() => {
        self.closeGraphFile(tabId)
      })
    },

    closeGraphFile(tabId) {
      const self = this
      const index = self.openedGraphTabs.findIndex(value => {
        return value.id === tabId
      })
      if (index !== -1) {
        // 关闭窗口时从缓存中删除当前文件内容
        GraphUtil.removeLocalstorageItem(self.openedGraphTabs[index].id)
        self.openedGraphTabs.splice(index, 1)
        self.$store.commit('removeGraphTab', tabId)
        if (self.openedGraphTabs.length > 0) {
          const newIndex = Math.max(0, Math.min(index + 1, self.openedGraphTabs.length - 1))
          self.change2CurrentGraphFile(self.openedGraphTabs[newIndex].title)
        } else {
          self.$store.commit('setCurrentGraphFile', null)
          self.graph.clearCells()
        }
      }
    },

    // 改变当前图形文件
    change2CurrentGraphFile(fileName) {
      const self = this
      const newTab = self.openedGraphTabs.find(value => { return value.title === fileName })
      if (!newTab) {
        return
      }
      self.activeTabName = newTab.id
      const oldGraphFile = self.$store.state.graphModule.currentGraphFile
      if (oldGraphFile !== null) {
        const oldTab = self.openedGraphTabs.find(value => { return value.title === oldGraphFile.title })
        // 将上一个图形文件的内容保存在缓存中
        if (oldTab) {
          var text = ConstantUtil.stringifyJson(self.graph.toJSON())
          GraphUtil.setLocalstorageItem(oldGraphFile.id, text)
        }
      }
      self.$store.commit('setCurrentGraphFile', newTab)
      GraphBehavier.reloadGraph(self, self.graph)
    }
  }
}
</script>

<style scoped>
.app-content {
  /* flex: 1; */
  margin-left: 8px;
  margin-right: 8px;
  box-shadow: 0 0 10px 1px #e9e9e9;
}

.map-container {
  width: 150px;
  height: 0px;
  position: relative; 
  left: 10px; 
  top: 0px;
}

.menu_item {
  display: block;
  height: 30px;
	line-height: 30px;
	text-align: center;
	margin:10px;
	cursor: default;
}
.menu_item:hover{
	color: #3d3fd8;
}

.menu_divider {
  margin: 2px 0;
}

.menu {
 	height: auto;
 	width: auto;
 	position: absolute;
 	font-size: 14px;
 	text-align: left;
 	border-radius: 10px;
 	border: 1px solid #c1c1c1;
 	background-color: #ffffff;
}

li:hover {
  background-color: #E0E0E2;
  color: white;
}

</style>